package cn.edu.hust.cm.lib;

/**
 * 用于测量代码执行的计时器
 */
public abstract class Clock {

    private long start;
    private long end;
    protected String name;
    
    private Clock() { }

    private final static Clock MILLIS_SECOND_CLOCK = new MillisClock("millis");

    private final static Clock NANO_SECOND_CLOCK = new NanoClock("nano");

    /**
     * 获得毫秒级别的计时器
     * @return
     */
    public static Clock getMillisSecondClock() {
        return MILLIS_SECOND_CLOCK;
    }
    
    /**
     * 获得毫秒级别的计时器
     * @return
     */
    public static Clock newMillisSecondClock(String name) {
    	return new MillisClock(name);
    }

    /**
     * 获得纳秒级别的计时器
     * @return
     */
    public static Clock getNanoSecondClock() {
        return NANO_SECOND_CLOCK;
    }
    
    /**
     * 获得纳秒级别的计时器
     * @return
     */
    public static Clock newNanoSecondClock(String name) {
    	return new NanoClock(name);
    }

    /**
     * 获得耗时
     * @return
     */
    public long spendTime() {
        if(end == 0L) {
            stop();
        }
        long spend = end - start;
        return spend;
    }
    
    /**
     * 启动计时器
     */
    public void start() {
    	end = 0L;
        start = getCurrentTime();
    }

    /**
     * 停止计时器
     */
    public void stop() {
        end = getCurrentTime();
    }

    /**
     * 获得当前计时器的时间
     * @return
     */
    protected abstract long getCurrentTime();

    /**
     * 打印计时结果
     * @param tag
     */
    public abstract void logSpendTime(String tag);
    
    static class MillisClock extends Clock {
    	
    	private MillisClock(String name) {
    		this.name = name;
    	}
    	
        protected long getCurrentTime() {
            return System.currentTimeMillis();
        }
        
        @Override
        public void logSpendTime(String tag) {
        	System.out.println(name + "" + tag + "cost time(ms): " + spendTime());
        }    	
    }
    
    static class NanoClock extends Clock {
    	
    	private NanoClock(String name) {
    		this.name = name;
    	}
    	
        protected long getCurrentTime() {
            return System.nanoTime();
        }
        
        public void logSpendTime(String tag) {
        	System.out.println(tag + "cost time(ns): " + spendTime());
        }    	
    }
}